package com.kaifamiao.wendao.controller;

import com.kaifamiao.wendao.entity.Customer;
import com.kaifamiao.wendao.service.CustomerService;
import com.kaifamiao.wendao.utils.StringHelper;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.logging.Logger;

@WebServlet( "/customer/*" )
public class CustomerServlet extends HttpServlet {

    private String prefix = "/customer";
    private Logger logger = Logger.getLogger( this.getClass().getName() );
    // 用实例变量来引用 CustomerService 实例
    private CustomerService customerService = new CustomerService();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取本次请求路径
        String uri = request.getRequestURI();
        // 获取请求方式(即相应的HTTP动作)
        String method = request.getMethod();
        logger.info( method + ":" + uri );
        // 获取请求路径中前缀的长度
        int begin = prefix.length() ;
        // 尝试从请求路径中获得首个分号的位置
        int end = uri.indexOf( ";") ;
        // 若请求路径中没有分号则以 uri 长度为结束位置
        end = end == -1 ? uri.length() : end ;
        // 从请求路径中截取前缀之后的内容
        String path = uri.substring( begin , end );
        logger.info( path );

        // 如果以 GET方式 请求 "/customer/sign/in" 则打开登录页面
        if( "/sign/in".equals( path ) && "GET".equals( method ) ){
            signInPage( request , response );
            return ;
        }

        // 如果以 POST方式 请求 "/customer/sign/in" 则需要处理登录请求
        if( "/sign/in".equals( path ) && "POST".equals( method ) ){
            signInAction( request , response );
            return ;
        }

        // 如果以 GET方式 请求 "/customer/sign/up" 则打开注册页面
        if( "/sign/up".equals( path ) && "GET".equals( method ) ){
            signUpPage( request , response );
            return ;
        }

        // 如果以 POST方式 请求 "/customer/sign/up" 则需要处理注册请求
        if( "/sign/up".equals( path ) && "POST".equals( method ) ){
            signUpAction( request , response );
            return ;
        }

        // 如果以 GET方式 请求 "/customer/sign/out" 则需要处理注销请求
        if( "/sign/out".equals( path ) && "GET".equals( method ) ){
            signOutAction( request , response );
            return ;
        }
    }

    // 用来跳转到登录页面
    private void signInPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        logger.info( "打开登录页面" );
        String path = "/WEB-INF/pages/customer/sign-in.jsp" ;
        RequestDispatcher dispatcher = request.getRequestDispatcher( path );
        dispatcher.forward( request , response );
    }

    // 用来实现登录操作
    private void signInAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        final String uri = request.getContextPath() + "/customer/sign/in" ;
        // 若请求参数未通过校验
        if( !this.signInValidate( request ) ) {
            // 则重定向到登录页面
            response.sendRedirect( uri );
            return;
        }

        // 获取请求参数
        String username = request.getParameter( "username" );
        String password = request.getParameter( "password" );
        Customer c = customerService.load( username );
        if( c == null ) {
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "用户名错误" );
            response.sendRedirect( uri );
            return;
        }
        // 使用数据库中存储的盐值对用户在界面上输入的密码进行混淆并加密
        String encrypted = customerService.process( password , c.getSalt() );
        // 将加密后的字符串与数据库中保存的密码进行比较
        if( !encrypted.equals( c.getPassword() ) ) {
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "用户名错误" );
            response.sendRedirect( uri );
            return;
        }
        // 将整个 Customer 对象作为值添加到 会话的属性中
        session.setAttribute( "customer" , c );
        // 登录成功后去往 话题列表页面
        response.sendRedirect( request.getContextPath() + "/topic/list" );
    }

    private boolean signInValidate( HttpServletRequest request ){
        HttpSession session = request.getSession();

        String username = request.getParameter( "username" );
        // username == null || username.trim().isEmpty()
        if( StringHelper.empty( username ) ){
            session.setAttribute( "message" , "用户名不可以为空" );
            return false ;
        }

        String password = request.getParameter( "password" );
        if( StringHelper.empty( password ) ){
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "密码不可以为空" );
            return false ;
        }

        // 获取用户输入的验证码字符串
        String captcha = request.getParameter( "captcha" );
        if( StringHelper.empty( captcha ) ){
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "验证码不能为空" );
            return false ;
        }
        // 因为在 CaptchaImageServlet 中通过 session.setAttribute( "CAPTCHA" , code ) 设置属性
        // 所以通过属性名 "CAPTCHA" 可以获得保存在会话对象中的 验证码字符串
        String code = (String)session.getAttribute( "CAPTCHA" );
        // 比较会话中保存的验证码字符串 是否【不等于】 用户输入的验证码字符串
        if( !code.equalsIgnoreCase( captcha ) ){
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "你输入的验证码是错误的" );
            return false ;
        }

        return true ;
    }

    // 用来打开注册页面
    private void signUpPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        logger.info( "打开注册页面" );
        String path = "/WEB-INF/pages/customer/sign-up.jsp" ;
        RequestDispatcher dispatcher = request.getRequestDispatcher( path );
        dispatcher.forward( request , response );
    }

    // 用来实现注册操作
    private void signUpAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        HttpSession session = request.getSession();

        if( this.sianUpValidate( request ) ) {
            // 获取请求参数
            String username = request.getParameter( "username" );
            String nickname = request.getParameter( "nickname" );
            String password = request.getParameter( "password" );
            // 获得注册时的IP地址
            String ip = request.getRemoteAddr();
            // 根据接受到的数据创建一个 Customer 实例
            Customer c = new Customer( username , password , nickname , ip );
            CustomerService cs = new CustomerService();
            // 调用 CustomerService中的 register方法继续处理 Customer 实例
            boolean result = cs.register( c );
            if( result ) {
                session.setAttribute( "message" , "注册成功" );
                response.sendRedirect(request.getContextPath() + "/customer/sign/in");
                return;
            }
            session.setAttribute( "message" , "注册失败" );
        }

        response.sendRedirect(  request.getContextPath() + "/customer/sign/up" );
    }

    private boolean sianUpValidate( HttpServletRequest request ){
        HttpSession session = request.getSession();

        String nickname = request.getParameter( "nickname" );
        // username == null || username.trim().isEmpty()
        if( StringHelper.empty( nickname ) ){
            session.setAttribute( "message" , "你不填个昵称吗?" );
            return false ;
        }

        String username = request.getParameter( "username" );
        // username == null || username.trim().isEmpty()
        if( StringHelper.empty( username ) ){
            session.setAttribute( "nickname" , nickname );
            session.setAttribute( "message" , "用户名不可以为空" );
            return false ;
        }

        String password = request.getParameter( "password" );
        if( StringHelper.empty( password ) ){
            session.setAttribute( "nickname" , nickname );
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "密码不可以为空" );
            return false ;
        }

        String confirm = request.getParameter( "confirm" );
        if( !password.equals( confirm ) ){
            session.setAttribute( "nickname" , nickname );
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "两次输入的密码不一致" );
            return false ;
        }

        // 获取用户输入的验证码字符串
        String captcha = request.getParameter( "captcha" );
        if( StringHelper.empty( captcha ) ){
            session.setAttribute( "nickname" , nickname );
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "验证码不能为空" );
            return false ;
        }
        // 因为在 CaptchaImageServlet 中通过 session.setAttribute( "CAPTCHA" , code ) 设置属性
        // 所以通过属性名 "CAPTCHA" 可以获得保存在会话对象中的 验证码字符串
        String code = (String)session.getAttribute( "CAPTCHA" );
        // 比较会话中保存的验证码字符串 是否【不等于】 用户输入的验证码字符串
        if( !code.equalsIgnoreCase( captcha ) ){
            session.setAttribute( "nickname" , nickname );
            session.setAttribute( "username" , username );
            session.setAttribute( "message" , "你输入的验证码是错误的" );
            return false ;
        }

        return true ;
    }

    // 用来实现注销操作
    private void signOutAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        session.removeAttribute( "customer" );
        response.sendRedirect( request.getContextPath() + "/topic/list" );
    }

}
